package com.engine.salary.report.wrapper;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONArray;
import com.cloudstore.eccom.pc.table.WeaTable;
import com.cloudstore.eccom.pc.table.WeaTableColumn;
import com.cloudstore.eccom.result.WeaResultMsg;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.cache.SalaryCacheKey;
import com.engine.salary.component.WeaFormOption;
import com.engine.salary.component.WeaTableColumnGroup;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.salaryitem.SalaryDataTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.report.common.constant.SalaryConstant;
import com.engine.salary.report.entity.bo.SalaryStatisticsReportBO;
import com.engine.salary.report.entity.param.*;
import com.engine.salary.report.entity.po.SalaryStatisticsDimensionPO;
import com.engine.salary.report.entity.po.SalaryStatisticsItemPO;
import com.engine.salary.report.entity.po.SalaryStatisticsPushPO;
import com.engine.salary.report.entity.po.SalaryStatisticsReportPO;
import com.engine.salary.report.service.*;
import com.engine.salary.report.service.impl.*;
import com.engine.salary.service.*;
import com.engine.salary.service.impl.*;
import com.engine.salary.util.*;
import com.engine.salary.util.excel.ExcelUtilPlus;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import weaver.general.PageIdConst;
import weaver.hrm.User;
import weaver.wechat.util.Utils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 薪酬统计维度
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
public class SalaryStatisticsReportWrapper extends Service {

    private static final String conditionId = "salaryStatisticsReportSearchCondition";

    private SalaryStatisticsReportService getSalaryStatisticsReportService(User user) {
        return ServiceUtil.getService(SalaryStatisticsReportServiceImpl.class, user);
    }

    private SalaryStatisticsItemService getSalaryStatisticsItemService(User user) {
        return ServiceUtil.getService(SalaryStatisticsItemServiceImpl.class, user);
    }

    private SalaryStatisticsDimensionService getSalaryStatisticsDimensionService(User user) {
        return ServiceUtil.getService(SalaryStatisticsDimensionServiceImpl.class, user);
    }

    private SubTableExportService getSubTableExportService(User user) {
        return ServiceUtil.getService(SubTableExportServiceImpl.class, user);
    }

    private SalaryAcctEmployeeService getSalaryAcctEmployeeService(User user) {
        return ServiceUtil.getService(SalaryAcctEmployeeServiceImpl.class, user);
    }

    private SalaryAcctResultService getSalaryAcctResultService(User user) {
        return ServiceUtil.getService(SalaryAcctResultServiceImpl.class, user);
    }

    private SalaryItemService getSalaryItemService(User user) {
        return ServiceUtil.getService(SalaryItemServiceImpl.class, user);
    }

    private SalaryCacheService getSalaryCacheService(User user) {
        return ServiceUtil.getService(SalaryCacheServiceImpl.class, user);
    }

    private SalaryStatisticsPushService getSalaryStatisticsPushService(User user) {
        return ServiceUtil.getService(SalaryStatisticsPushServiceImpl.class, user);
    }

    private SalaryStatisticsPushDetailService getSalaryStatisticsPushDetailService(User user) {
        return ServiceUtil.getService(SalaryStatisticsPushDetailServiceImpl.class, user);
    }

    private TaxAgentService getTaxAgentService(User user) {
        return ServiceUtil.getService(TaxAgentServiceImpl.class, user);
    }


    /**
     * 报表列表
     *
     * @param queryParam
     * @return
     */
    public List<Map<String, Object>> list(SalaryStatisticsReportQueryParam queryParam) {
        Long uid = Long.valueOf(user.getUID());
        // 初始化
        getSalaryStatisticsDimensionService(user).init(uid);

        // 所有人能够看到自己创建的报表,薪酬总管理员能够查看所有报表
        List<SalaryStatisticsReportPO> reportList = getSalaryStatisticsReportService(user).listByCreator(uid);
        List<Long> reportIds = reportList.stream().map(SalaryStatisticsReportPO::getId).collect(Collectors.toList());
        // 获取所有没有撤回没有过期的报表ID（不包含过期失效的）
        List<SalaryStatisticsPushPO> pushList = getSalaryStatisticsPushService(user).getSuccessPushListByReceiver(uid);
        List<Long> sharedReportIds = pushList.stream().map(po -> Arrays.asList(StringUtils.split(po.getReportIds(), ",")))
                .flatMap(Collection::stream).distinct().map(Long::valueOf).collect(Collectors.toList());
        sharedReportIds = sharedReportIds.stream().filter(id -> !reportIds.contains(id)).collect(Collectors.toList());
        reportList.addAll(getSalaryStatisticsReportService(user).getByIds(sharedReportIds));

        if (StringUtils.isNotEmpty(queryParam.getReportName())) {
            reportList = reportList.stream().filter(rp -> rp.getReportName().contains(queryParam.getReportName())).collect(Collectors.toList());
        }
        List<SalaryStatisticsDimensionPO> salaryStatisticsDimensionList = this.getSalaryStatisticsDimensionService(user).listAll();
        Map<String, String> salaryStatisticsDimensionMap = SalaryEntityUtil.convert2Map(salaryStatisticsDimensionList, k -> k.getId().toString(), SalaryStatisticsDimensionPO::getDimName);
        List<Map<String, Object>> result = new ArrayList<>();
        List<Long> finalSharedReportIds = sharedReportIds;
        reportList.forEach(po -> {
            Map<String, Object> temp = new HashMap<>();
            temp.put("id", po.getId().toString());
            temp.put("reportName", po.getReportName());
            temp.put("timeType", po.getTimeType() == null ? 10 : po.getTimeType());
            temp.put("salaryStartMonth", SalaryDateUtil.getFormatYearMonth(po.getSalaryStartMonth()));
            temp.put("salaryEndMonth", SalaryDateUtil.getFormatYearMonth(po.getSalaryEndMonth()));
            List<String> dimNames = Arrays.stream(po.getDimension().split(",")).map(dim -> Optional.ofNullable(salaryStatisticsDimensionMap.get(dim)).orElse("")).collect(Collectors.toList());
            temp.put("dimension", StringUtils.join(dimNames, ","));
            temp.put("dimensionId", po.getDimension());
            temp.put("isShare", finalSharedReportIds.contains(po.getId()));
            result.add(temp);
        });
        return result;
    }

    /**
     * 获取薪酬统计报表表单
     *
     * @param id
     * @param
     * @return
     */
    public Map<String, Object> getFrom(Long id) {

        List<SalaryStatisticsDimensionPO> salaryStatisticsDimensions = getSalaryStatisticsDimensionService(user).listAll();

        List<WeaFormOption> statsDimOptions = salaryStatisticsDimensions.stream().map(sd -> new WeaFormOption(sd.getId().toString(), sd.getDimName())).collect(Collectors.toList());

        // 获取默认维度统计
        List<SalaryStatisticsDimensionPO> defaultSalaryStatisticsDimensions = getSalaryStatisticsDimensionService(user).listAllDefaultDimension();
        List<Long> defaultDimensionIds = defaultSalaryStatisticsDimensions.stream().map(SalaryStatisticsDimensionPO::getId).collect(Collectors.toList());
        // 获取有薪资统计报表引用的统计维度
        Set<String> haveUsedDimIds = new HashSet<>();
        List<SalaryStatisticsReportPO> salaryStatisticsReports = getSalaryStatisticsReportService(user).listAll();
        salaryStatisticsReports.stream().forEach(report -> Collections.addAll(haveUsedDimIds, report.getDimension().split(",")));
        statsDimOptions.stream().forEach(option -> {
            if (defaultDimensionIds.contains(Long.valueOf(option.getId()))) {
                // 默认维度不允许修改、删除
                option.setCanDelete(false);
                option.setCanEdit(false);
            } else if (haveUsedDimIds.contains(option.getId())) {
                // 被薪资统计报表引用的不能删除
                option.setCanEdit(true);
                option.setCanDelete(false);
            }
        });

        // 1.构建基础信息表单
        Map<String, Object> weaForm = new HashMap<>();
        weaForm.put("statsDimOptions", statsDimOptions);


        if (id != null) {
            SalaryStatisticsReportPO po = this.getSalaryStatisticsReportService(user).getById(id);
            if (po == null) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161845, "薪酬统计报表不存在"));
            }
            Map<String, Object> dataMap = JsonUtil.parseMap(po, Object.class);
            dataMap.put("dimension", Arrays.asList(po.getDimension().split(",")));
            weaForm.put("data", dataMap);
        }

        return weaForm;
    }

    /**
     * 保存薪酬统计报表
     *
     * @param saveParam
     * @param
     * @return
     */
    public String save(SalaryStatisticsReportSaveParam saveParam) {
        return getSalaryStatisticsReportService(user).save(saveParam);
    }

    /**
     * 删除薪酬统计报表
     *
     * @param ids
     * @param
     * @return
     */
    public Map<String, Object> delete(Collection<Long> ids) {
        return getSalaryStatisticsReportService(user).delete(ids);
    }

    /**
     * 复制薪资账套
     *
     * @param id
     */
    public void duplicate(Long id) {
        if (id == null) {
            throw new SalaryRunTimeException("id为空");
        }
        getSalaryStatisticsReportService(user).duplicate(id);
    }

    /**
     * 获取统计条件
     *
     * @param id
     * @return
     */
    public Map<String, Object> getSearchCondition(Long id) {
        // 高级搜索实例
        Map<String, Object> map = new HashMap<>();

        if (id != null) {
            SalaryStatisticsReportPO po = getSalaryStatisticsReportService(user).getById(id);
            SalaryAssert.notNull(po, SalaryI18nUtil.getI18nLabel(152563, "报表不存在"));

            Map<String, Object> data = new HashMap<>();
            data.put("timeType", po.getTimeType() == null ? 10 : po.getTimeType());
            data.put("salaryStartMonth", SalaryDateUtil.getFormatYearMonth(po.getSalaryStartMonth()));
            data.put("salaryEndMonth", SalaryDateUtil.getFormatYearMonth(po.getSalaryEndMonth()));
            data.put("taxAgent", JSONArray.parseArray(po.getTaxAgentSetting()));
            data.put("salarySob", JSONArray.parseArray(po.getSalarySobSetting()));
            data.put("incomeCategory", JSONArray.parseArray(po.getIncomeCategorySetting()));
            data.put("subCompany", JSONArray.parseArray(po.getSubCompanySetting()));
            data.put("department", JSONArray.parseArray(po.getDepartSetting()));
            data.put("grade", JSONArray.parseArray(po.getGradeSetting()));
            data.put("position", JSONArray.parseArray(po.getPositionSetting()));
            data.put("status", JSONArray.parseArray(po.getStatusSetting()));
            data.put("employee", JSONArray.parseArray(po.getEmployeeSetting()));
            data.put("hiredate", JSONArray.parseArray(po.getHiredateSetting()));
//            data.put("leavedate", JSONArray.parseArray(po.getLeavedateSetting()));

            map.put("data", data);
        }

        return map;
    }


    public String saveSearchCondition(SalaryStatisticsSearchConditionSaveParam param) {
        return this.getSalaryStatisticsReportService(user).saveSearchCondition(param);
    }

    /**
     * 获取报表数据
     *
     * @param param
     * @return
     */
    public Map<String, Object> getData(SalaryStatisticsReportDataQueryParam param) {
        Long id = param.getId();
        if (id == null || param.getDimensionId() == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }
        SalaryStatisticsDimensionPO dimension = getSalaryStatisticsDimensionService(user).getById(param.getDimensionId());
        if (dimension == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161300, "统计维度不存在"));
        }
        // 查询报表配置
        SalaryStatisticsReportPO po = this.getSalaryStatisticsReportService(user).getById(id);
        if (po == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161845, "薪酬统计报表不存在"));
        }
        if (param.isShare()) {
            // 是被分享的报表
            Long uid = Long.valueOf(user.getUID());
            // 校验查看权限，获取有效的分享记录
            List<SalaryStatisticsPushPO> pushList = getSalaryStatisticsPushService(user).shareReportValid(param.getId(), uid);
            List<Long> batchIds = pushList.stream().map(SalaryStatisticsPushPO::getId).collect(Collectors.toList());
            getSalaryStatisticsPushService(user).updateReportViewStatus(batchIds, uid);
//            salaryStatisticsPushService.sendViewedMsg(param.getBatchId(), param.getId(), employeeId, tenantKey);
            // 如果是被分享的报表，校验分享权限，通过后将user赋值为报表创建人
            User creator = new User();
            creator.setUid(po.getCreator().intValue());
            user = creator;
        } else {
            // 判断报表是否是登陆人创建的,或薪酬总管理员
            Boolean needAuth = getTaxAgentService(user).isNeedAuth((long) user.getUID());
            if (needAuth && NumberUtils.compare(po.getCreator().intValue(), user.getUID()) != 0) {
                throw new SalaryRunTimeException("无权限查看该报表！");
            }
        }

        // weaTable对象
        Map<String, Object> weaTable = new HashMap<>();

        // 查询自定义统计项目
        List<SalaryStatisticsItemPO> salaryStatisticsItemList = this.getSalaryStatisticsItemService(user).listByStatisticsReportId(po.getId());

        // 参数转换
        SalaryStatisticsReportBO.poToQueryParam(param, po);
        String paramMd5 = SecureUtil.md5(param + salaryStatisticsItemList.toString());

        //已缓存的报表id
        String salaryReportIds = Utils.null2String(getSalaryCacheService(user).get(SalaryCacheKey.SALARY_REPORT_IDS));
        String salaryReportConditions = "";
        // 获取人员维度id
        Optional<Long> empDimensionOptional = getSalaryStatisticsDimensionService(user).listAllDefaultDimension().stream().filter(dim -> dim.getDimName().equals("人员")).map(SalaryStatisticsDimensionPO::getId).findFirst();
        Long empDimensionId = 0L;
        if (empDimensionOptional.isPresent()) {
            empDimensionId = empDimensionOptional.get();
        }
//        if (StringUtils.isNotBlank(salaryReportIds) && salaryReportIds.contains(id + "")) {
//            //报表中缓存的条件
//            salaryReportConditions = Utils.null2String(getSalaryCacheService(user).get(SalaryCacheKey.SALARY_REPORT_CONDITIONS + id));
//            if (StringUtils.isNotBlank(salaryReportConditions) && salaryReportConditions.contains(paramMd5)) {
//                Map<String, Object> result = getSalaryCacheService(user).get(SalaryCacheKey.SALARY_REPORT_DATA + id + "_" + paramMd5);
//                if (param.getDimensionId().equals(empDimensionId)) {
//                    // 人员维度需要分页
//                    Map<String, Object> finalResultMap = new HashMap<>();
//                    PageInfo<Map<String, Object>> pageInfo = (PageInfo<Map<String, Object>>) result.get("pageInfo");
//                    PageInfo<Map<String, Object>> finalPageInfo = SalaryPageUtil.buildPage(param.getCurrent(), param.getPageSize());
//                    finalPageInfo.setTotal(pageInfo.getList().size());
//                    finalPageInfo.setList(SalaryPageUtil.subList(param.getCurrent(), param.getPageSize(), pageInfo.getList()));
//                    finalResultMap.put("pageInfo", finalPageInfo);
//                    finalResultMap.put("columns", result.get("columns"));
//                    finalResultMap.put("countResult", result.get("countResult"));
//                    finalResultMap.put("reportId", id);
//                    return finalResultMap;
//                }
//
//                return result;
//            }
//        }


        // 列表data
        PageInfo<Map<String, Object>> page = this.getSalaryStatisticsReportService(user).buildReportRecords(dimension, param, salaryStatisticsItemList);

        // 组装合计
        Map<String, Object> countResultMap = SalaryStatisticsReportBO.buildTotal(page, salaryStatisticsItemList, (long) user.getUID());

        // 列表columns
        List<WeaTableColumnGroup> weaTableColumns = SalaryStatisticsReportBO.buildReportColumns(dimension, salaryStatisticsItemList);

        Map<String, Object> resultMap = Maps.newHashMap();
        resultMap.putAll(JsonUtil.parseMap(weaTable, Object.class));
        resultMap.put("columns", weaTableColumns);
        resultMap.put("pageInfo", page);
        resultMap.put("countResult", countResultMap);
        resultMap.put("reportId", id);


        //设置报表缓存
        getSalaryCacheService(user).set(SalaryCacheKey.SALARY_REPORT_IDS, salaryReportIds + "," + id);
        getSalaryCacheService(user).set(SalaryCacheKey.SALARY_REPORT_CONDITIONS + id, salaryReportConditions + "," + paramMd5);
        getSalaryCacheService(user).set(SalaryCacheKey.SALARY_REPORT_DATA + id + "_" + paramMd5, resultMap);

        Map<String, Object> finalResultMap = Maps.newHashMap();
        // 缓存完之后结果分页
        if (param.getDimensionId().equals(empDimensionId)) {
            // 只有是人员维度才分页
            PageInfo<Map<String, Object>> pageInfo = SalaryPageUtil.buildPage(param.getCurrent(), param.getPageSize());
            pageInfo.setTotal(page.getList().size());
            pageInfo.setList(SalaryPageUtil.subList(param.getCurrent(), param.getPageSize(), page.getList()));
            finalResultMap.put("pageInfo", pageInfo);
            finalResultMap.put("columns", weaTableColumns);
            finalResultMap.put("countResult", countResultMap);
            finalResultMap.put("reportId", id);

            return finalResultMap;
        }

        return resultMap;
    }


    /**
     * 导出报表数据
     *
     * @param param
     * @return
     */
    public Map<String, Object> exportData(SalaryStatisticsReportDataQueryParam param) {
        Long id = param.getId();
        if (id == null || param.getDimensionId() == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }

        SalaryStatisticsReportPO po = this.getSalaryStatisticsReportService(user).getById(id);
        if (po == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161845, "薪酬统计报表不存在"));
        }
        SalaryStatisticsDimensionPO dimension = getSalaryStatisticsDimensionService(user).getById(param.getDimensionId());
        if (dimension == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161300, "统计维度不存在"));
        }
        sharedReportCheck(param.isShare(), po);

        // 查询自定义统计项目
        List<SalaryStatisticsItemPO> salaryStatisticsItemList = this.getSalaryStatisticsItemService(user).listByStatisticsReportId(po.getId());
        // 参数转换
        SalaryStatisticsReportBO.poToQueryParam(param, po);
        String paramMd5 = SecureUtil.md5(param + salaryStatisticsItemList.toString());

        //已缓存的报表id
        String salaryReportIds = Utils.null2String(getSalaryCacheService(user).get(SalaryCacheKey.SALARY_REPORT_IDS));
        String salaryReportConditions = "";

        if (StringUtils.isNotBlank(salaryReportIds) && salaryReportIds.contains(id + "")) {
            //报表中缓存的条件
            salaryReportConditions = Utils.null2String(getSalaryCacheService(user).get(SalaryCacheKey.SALARY_REPORT_CONDITIONS + id));
            if (StringUtils.isNotBlank(salaryReportConditions) && salaryReportConditions.contains(paramMd5)) {
                Map<String, Object> result = getSalaryCacheService(user).get(SalaryCacheKey.SALARY_REPORT_DATA + id + "_" + paramMd5);
                // 获取列头
                List<WeaTableColumnGroup> weaTableColumns = (List<WeaTableColumnGroup>) result.get("columns");
                PageInfo<Map<String, Object>> page = (PageInfo<Map<String, Object>>) result.get("pageInfo");
                Map<String, Object> countResultMap = (Map<String, Object>) result.get("countResult");
                List<Map<String, Object>> list = page.getList();
                // 获取数据
                List<Map<String, Object>> records = list.stream().map(m -> m.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() == null ? "" : e.getValue()))).collect(Collectors.toList());
                records.add(countResultMap);

                List rows = new ArrayList<>();
                rows.add(weaTableColumns);

                List<String> head = new ArrayList<>();
                weaTableColumns.forEach(weaTableColumn -> {
                    String column = weaTableColumn.getColumn();
                    if (CollectionUtils.isEmpty(weaTableColumn.getChildren())) {
                        head.add(column);
                    } else {
                        weaTableColumn.getChildren().forEach(children -> {
                            head.add(children.getColumn());
                        });
                    }
                });

                List<Long> itemIds = salaryStatisticsItemList.stream().map(item -> item.getItemValue().split(",")).flatMap(Arrays::stream).filter(NumberUtils::isCreatable).map(Long::valueOf).collect(Collectors.toList());
                List<SalaryItemPO> salaryItemPOList = getSalaryItemService(user).listByIds(itemIds);
                List<String> numberItemIds = salaryItemPOList.stream().filter(item -> item.getDataType().equals(SalaryDataTypeEnum.NUMBER.getValue())).map(salaryItemPO -> salaryItemPO.getId().toString()).collect(Collectors.toList());
                Map<String, SalaryStatisticsItemPO> salaryStatisticsItemMap = SalaryEntityUtil.convert2Map(salaryStatisticsItemList, statisticsItemPO -> statisticsItemPO.getId().toString());

                for (Map<String, Object> map : records) {
                    List<Object> row = Lists.newArrayListWithExpectedSize(records.size());
                    head.forEach(k -> {
                        // 获取是数值还是文本
                        if (k.contains(SalaryStatisticsReportBO.UD)) {
                            String[] split = k.split(SalaryStatisticsReportBO.UD);
                            String salaryItemId = split[0];
                            SalaryStatisticsItemPO salaryStatisticsItemPO = salaryStatisticsItemMap.get(salaryItemId);
                            if (salaryStatisticsItemPO != null) {
                                Optional<String> textItemOptional = Arrays.stream(salaryStatisticsItemPO.getItemValue().split(",")).filter(itemId -> !numberItemIds.contains(itemId)).findFirst();
                                row.add((!textItemOptional.isPresent() && NumberUtils.isCreatable(Utils.null2String(map.get(k)).replaceAll(",", ""))) ? new BigDecimal(Utils.null2String(map.get(k)).replaceAll(",", "")) : map.getOrDefault(k, StringUtils.EMPTY));
                            } else {
                                row.add(map.getOrDefault(k, StringUtils.EMPTY));
                            }
                        } else {
                            row.add(map.getOrDefault(k, StringUtils.EMPTY));
                        }
                    });
                    rows.add(row);
                }

                String sheetName = SalaryI18nUtil.getI18nLabel(179263, "薪酬统计报表") + "-" + dimension.getDimName();
                XSSFWorkbook book = ExcelUtilPlus.genWorkbookWithChildTitleColumn(rows, sheetName, true);

                Map<String, Object> map = new HashMap<>();
                map.put("workbook", book);
                map.put("fileName", sheetName);

                // 记录操作日志
                String name = SalaryI18nUtil.getI18nLabel(0, "导出");
                LoggerContext loggerContext = new LoggerContext<>();
                loggerContext.setTargetId(po.getId().toString());
                loggerContext.setTargetName(po.getReportName());
                loggerContext.setOperateType(OperateTypeEnum.EXCEL_EXPORT.getValue());
                loggerContext.setOperateTypeName(name);
                loggerContext.setOperatedesc(name + SalaryI18nUtil.getI18nLabel(0, "薪酬统计报表") + "-" + po.getReportName());
                loggerContext.setUser(user);
                SalaryElogConfig.salaryStatReportLoggerTemplate.write(loggerContext);

                return map;
            }
        }

        throw new SalaryRunTimeException("未查询报表数据！");
    }

    /**
     * 获取报表透视数据
     *
     * @param param
     * @return
     */
    public Map<String, Object> getDataPerspective(SalaryStatisticsDataPerspectiveQueryParam param) {
        if (param.getId() == null || param.getDimensionId() == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }
        SalaryStatisticsReportPO po = this.getSalaryStatisticsReportService(user).getById(param.getId());
        if (po == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161845, "薪酬统计报表不存在"));
        }
        SalaryStatisticsDimensionPO dimension = getSalaryStatisticsDimensionService(user).getById(param.getDimensionId());
        if (dimension == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161300, "统计维度不存在"));
        }
        // 校验报表权限，如果是被分享报表修改User
        sharedReportCheck(param.isShare(), po);
        // 查询自定义统计项目中所有薪资项目id
        List<SalaryStatisticsItemPO> salaryStatisticsItemPOS = getSalaryStatisticsItemService(user).listByStatisticsReportId(param.getId());
        List<Long> salaryItemIds = salaryStatisticsItemPOS.stream().filter(item -> StringUtils.isNotBlank(item.getItemValue())).map(p -> p.getItemValue().split(","))
                .flatMap(Arrays::stream).map(Long::valueOf).collect(Collectors.toList());

        PageInfo<Map<String, Object>> pageInfo = getSalaryStatisticsReportService(user).buildDataPerspectiveRecords(param, po, dimension, salaryStatisticsItemPOS);

        List<SalaryItemPO> itemList = getSalaryItemService(user).listByIds(salaryItemIds);
        // 列表columns
        List<WeaTableColumn> weaTableColumns = buildDataPerspectiveTableColumns(itemList, salaryItemIds);

        WeaTable table = new WeaTable();
        String pageId = "a4f85an7-9576-4125-adn9-7d06e7sy69f2";
        table.setPageID(pageId);
        table.setPageUID(pageId + user.getUID());
        table.setPagesize(PageIdConst.getPageSize(pageId, user.getUID()));
        table.setBackfields("");

        table.setColumns(weaTableColumns);

        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();

        // 结果
        Map<String, Object> resultMap = Maps.newHashMap();
        resultMap.put("dataKey", result.getResultMap());
        resultMap.put("pageInfo", pageInfo);
        return resultMap;
    }

    /**
     * 获取报表透视数据
     *
     * @param param
     * @return
     */
    public Map<String, Object> exportDataPerspective(SalaryStatisticsDataPerspectiveQueryParam param) {
        if (param.getId() == null || param.getDimensionId() == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }
        SalaryStatisticsReportPO po = this.getSalaryStatisticsReportService(user).getById(param.getId());
        if (po == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161845, "薪酬统计报表不存在"));
        }
        SalaryStatisticsDimensionPO dimension = getSalaryStatisticsDimensionService(user).getById(param.getDimensionId());
        if (dimension == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(161300, "统计维度不存在"));
        }
        // 校验报表权限，如果是被分享报表修改User
        sharedReportCheck(param.isShare(), po);
        // 查询自定义统计项目中所有薪资项目id
        List<SalaryStatisticsItemPO> salaryStatisticsItemPOS = getSalaryStatisticsItemService(user).listByStatisticsReportId(param.getId());
        List<Long> salaryItemIds = salaryStatisticsItemPOS.stream().filter(item -> StringUtils.isNotBlank(item.getItemValue())).map(p -> p.getItemValue().split(","))
                .flatMap(Arrays::stream).map(Long::valueOf).collect(Collectors.toList());

        param.setCurrent(1);
        param.setPageSize(1000000000);
        PageInfo<Map<String, Object>> pageInfo = getSalaryStatisticsReportService(user).buildDataPerspectiveRecords(param, po, dimension, salaryStatisticsItemPOS);


        List<List<Object>> resultList = new ArrayList<>();

        List<SalaryItemPO> itemList = getSalaryItemService(user).listByIds(salaryItemIds);
        // 表格表头
        List<WeaTableColumn> weaTableColumns = buildDataPerspectiveTableColumns(itemList, salaryItemIds);
        List<Object> columns = new ArrayList<>();
        for (WeaTableColumn column : weaTableColumns) {
            columns.add(column.getText());
        }
        resultList.add(columns);

        List<Map<String, Object>> list = pageInfo.getList();
        for (Map<String, Object> resultMap : list) {
            List<Object> row = new ArrayList<>();
            for (WeaTableColumn column : weaTableColumns) {
                try {
                    if (StringUtils.isNotBlank(column.getOtherpara()) && column.getOtherpara().equals(SalaryDataTypeEnum.NUMBER.getValue())) {
                        // 数值
                        row.add(new BigDecimal(resultMap.get(column.getColumn()).toString()));
                    } else {
                        row.add(Utils.null2String(resultMap.get(column.getColumn())));
                    }
                } catch (Exception e) {
                    row.add(Utils.null2String(resultMap.get(column.getColumn())));
                }
            }
            resultList.add(row);
        }

        String sheetName = SalaryI18nUtil.getI18nLabel(179263, "薪酬统计报表明细") + "-" + dimension.getDimName();
        XSSFWorkbook book = ExcelUtilPlus.genWorkbookV2(resultList, sheetName);

        Map<String, Object> map = new HashMap<>();
        map.put("workbook", book);
        map.put("fileName", sheetName);
        return map;
    }

    /**
     * 权限校验
     *
     * @param isShared 是否是被分享的报表
     * @param po       报表po
     */
    private void sharedReportCheck(boolean isShared, SalaryStatisticsReportPO po) {
        if (isShared) {
            // 是被分享的报表
            Long uid = Long.valueOf(user.getUID());
            // 校验分享查看权限
            getSalaryStatisticsPushService(user).shareReportValid(po.getId(), uid);
            // 如果是被分享的报表，校验分享权限，通过后将user赋值为报表创建人
            User creator = new User();
            creator.setUid(po.getCreator().intValue());
            user = creator;
        } else {
            // 判断报表是否是登陆人创建的,或薪酬总管理员
            Boolean needAuth = getTaxAgentService(user).isNeedAuth((long) user.getUID());
            if (needAuth && NumberUtils.compare(po.getCreator().intValue(), user.getUID()) != 0) {
                throw new SalaryRunTimeException("无权限查看该报表！");
            }
        }
    }

    private List<WeaTableColumn> buildDataPerspectiveTableColumns(List<SalaryItemPO> salaryItems, List<Long> salaryItemIds) {
        Map<Long, SalaryItemPO> salaryItemMap = SalaryEntityUtil.convert2Map(salaryItems, SalaryItemPO::getId);
        // 表格表头
        List<WeaTableColumn> columns = new ArrayList<>();
        columns.add(new WeaTableColumn("100px", SalaryI18nUtil.getI18nLabel(87614, "姓名"), "userName"));
        columns.add(new WeaTableColumn("100px", SalaryI18nUtil.getI18nLabel(87614, "部门"), "departmentName"));
        columns.add(new WeaTableColumn("100px", SalaryI18nUtil.getI18nLabel(87614, "薪资所属月"), "salaryMonth"));
        columns.add(new WeaTableColumn("100px", SalaryI18nUtil.getI18nLabel(86184, "个税扣缴义务人"), "taxAgent"));
        columns.add(new WeaTableColumn("100px", SalaryI18nUtil.getI18nLabel(86184, "账套"), "salarySob"));
//        columns.add(new WeaTableColumn("100px", SalaryI18nUtil.getI18nLabel(86184, "次数"), "acctTimes").setDisplay(WeaBoolAttr.FALSE));
        salaryItemIds.forEach(itemId -> {
            SalaryItemPO item = salaryItemMap.get(itemId);
            if (item != null) {
                WeaTableColumn weaTableColumn = new WeaTableColumn("100px", item.getName(), item.getId() + SalaryConstant.DYNAMIC_SUFFIX);
                weaTableColumn.setOtherpara(item.getDataType());
                columns.add(weaTableColumn);
            }
        });
        return columns;
    }
}
